﻿using System;
using System.Collections.Generic;
using System.Text;

namespace sign_recognition
{
    public class Category : IComparable<Category>
    {

        public String output;
        public Double T;

        public Double jIndex;//index of the neuron in the layer, from 0, 1, 2...

        /// <summary>
        /// A neuron of F2 represents one category formed by the network and is caracterized by its
        /// weight vector wj (j is the index of the neuron)
        /// </summary>
        public Double[] w;//Every connection is weighted by a number lying between 0 and 1
        public Category()//The weight vector's size is equal to the dimension M of layer F1.
        {

        }
        public Category(int weightVectorsSize, int jIndex)//The weight vector's size is equal to the dimension M of layer F1.
        {
            this.output = "-1";//the result
            this.jIndex = jIndex;
            this.T = -1;


            w = new Double[weightVectorsSize];
            for (int i = 0; i < weightVectorsSize; i++)
            {
                w[i] = 1;//Initially all the weight vectors' components are fixed to 1. Until the weights of a neuron are modified, we say that it is uncommited.Inversely, once a neuron's weights have been modified, this neuron is said to be commited.
            }
        }
        public Category(Weights w)
        {
            this.output = w.output;//the result
            this.jIndex = -1;
            this.T = -1;


            this.w = new Double[w.values.Length];
            for (int i = 0; i < this.w.Length; i++)
            {
                this.w[i] = w.values[i];
            }
        }
        public int CompareTo(Category category_param)
        {
           // Category category_param = (Category)(category);

            if (this.T<category_param.T){
                return 1;
            }
            else if (this.T > category_param.T)
            {
                return -1;
            }
            else 
            {
                return 0;
            }
        }
        
        /// <summary>
        /// Modifies the weight vector.
        /// When the Fuzzy ART enters resonance, it proceeds with the learning of the 
        /// input vector I by modifying the weight vector wJ of the neuron
        /// </summary>
        public void modifyWeightVector(Double[] I, Double Beta,String output)
        {
            this.w = computeAddition(computeScalarMultiplication(Beta,fuzzyAND(w, I)), computeScalarMultiplication(1-Beta,w));
            this.output = output;

        }
        /// <summary>
        /// Choice function: to choose the smallest box in which
        /// the point is included. A point is said to be in a box when the weight vector wj
        /// corresponding to this box is a fuzzy subset of the input vector I.
        /// </summary>
        /// <param name="I">The I.</param>
        public void choiceFunction(Double[] I, Double Alpha)
        {


           this.T = this.computeNorm(fuzzyAND(I, w)) / (Alpha + computeNorm(w));

   





















        }
        /// <summary>
        /// A vigilance criteron is evaluated.
        /// The vigilance criterion causes the network to choose another box (neuron)
        /// if the one chosen is already too large.
        /// Rho is the vigilance parameter, which lies in the interval [0, 1]. Controls the maximum size of hyperboxes.
        /// 
        /// 
        /// </summary>
        /// <returns></returns>
        public bool evaluateVigilanceCriterion(Double[] I, Double Rho)
        {
            double a= computeNorm(fuzzyAND(I, w));
            double b=computeNorm(I);
            double criterion = a/ b;
            if (criterion >= Rho)
            {
                return true;
            }else{
                return false;
            }

        }
        /// <summary>
        /// z=min(x, y,)
        /// </summary>
        /// <param name="x">x</param>
        /// <param name="y">y</param>
        /// <returns></returns>
        public Double[] fuzzyAND(Double[] x, Double[] y) {
            
            if (x.Length != y.Length)
            {
                Console.WriteLine("ERROR: FuzzyAnd no realizado, vectores difieren en tamaño.");
                return null;
            }
            Double[] z = new Double[x.Length];
            for (int i = 0; i < z.Length; i++)
            {
                z[i] = Math.Min(x[i], y[i]);
            }
            return z;
        }
        public String doubleArrayToString(Double[] x)
        {
            String array = "";
            for (int i = 0; i < x.Length; i++)
            {
                array += "(" + x[i] + ")";
            }
            return array;
        }
        /// <summary>
        /// The sum of its components
        /// </summary>
        /// <param name="x">The x.</param>
        /// <returns></returns>
        public Double computeNorm(Double[] x) {
            Double norm=0.0;
            for (int i = 0; i <x.Length; i++)
            {
                norm = norm + x[i];
            }
            return norm;
        }
        /// <summary>
        /// Computes the scalar multiplication.
        /// </summary>
        /// <returns></returns>
        public Double[] computeScalarMultiplication(Double scalar, Double[] x){

            Double[] result= new Double[x.Length];
            for(int i=0; i<x.Length; i++){
                result[i] = x[i] * scalar;
            }
            return result;
        }
        /// <summary>
        /// Computes the addition.
        /// </summary>
        /// <returns></returns>
        public Double[] computeAddition(Double[] x, Double[] y) {
            Double[] result = new Double[x.Length];
            if(x.Length!=y.Length){
                Console.WriteLine("ERROR: Vectores incompatibles");
            }
            for (int i = 0; i <x.Length; i++)
            {
                result[i] = x[i] + y[i];
            }
            return result;
        }

        public override string ToString()
        {
            String content = "[T("+this.jIndex+"): " + this.T + "][weights:"; 

           /* foreach (Double i in this.w)
            {

                content += " " +i +" ";
            }*/


            content += "] {output: "+this.output+"}";
            return content;
        }
    }
}
